package com.untrance.shop.core.service.bean;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.untrance.shop.common.vo.CategoryVO;
import com.untrance.shop.core.builder.vo.CategoryVOBuilder;
import com.untrance.shop.core.comparator.CategoryLevelComparator;
import com.untrance.shop.core.dao.CategoryDao;
import com.untrance.shop.core.service.CategoryService;
import com.untrance.shop.model.Category;

/**
 * @author eugene zadyra
 */
@Service("categoryService")
public class CategoryServiceBean implements CategoryService {
	@Autowired
	private CategoryDao categoryDao;

	public CategoryServiceBean() {
	}

	public CategoryServiceBean(CategoryDao categoryDao) {
		this.categoryDao = categoryDao;
	}

	/**
	 * Get category tree by selected category key. This method required for
	 * displaying catalog tree on the page.
	 */
	@Override
	public List<Category> getCategoriesTreeByKey(Key key) {
		List<Category> list = new ArrayList<Category>();
		if (key == null) {
			list = categoryDao.findFirstLevelCategory();
		} else {
			Category current = categoryDao.find(key);
			if (current != null) {
				List<Category> currentResults = new ArrayList<Category>();
				List<Category> children = categoryDao.findChildrenByParentCategoryKey(current.getId());
				if (children != null) {
					currentResults.addAll(children);
				}
				current.setChildren(currentResults);
				Category c = current;
				for (int i = 0; i < current.getLevel() + 1; i++) {
					if (c.getParentCategoryKey() != null) {
						Category parent = categoryDao.find(c.getParentCategoryKey());
						List<Category> results = new ArrayList<Category>();
						results.addAll(categoryDao.findChildrenByParentCategoryKey(parent.getId()));
						parent.setChildren(results);
						findCurrentAndReplace(parent.getChildren(), c);
						c = parent;
					} else {
						List<Category> results = new ArrayList<Category>();
						results.addAll(categoryDao.findChildrenByParentCategoryKey(c.getParentCategoryKey()));
						list = results;
						findCurrentAndReplace(list, c);
					}
				}
			}
		}
		return list;
	}

	@Override
	public List<CategoryVO> getCategoriesVOTreeByKey(Key key) {
		List<Category> categories = getCategoriesTreeByKey(key);
		return new CategoryVOBuilder().createVOList(categories);
	}

	private void findCurrentAndReplace(List<Category> children, Category c) {
		for (int i = 0; i < children.size(); i++) {
			Category category = children.get(i);
			if (KeyFactory.keyToString(category.getId()).equals(KeyFactory.keyToString(c.getId()))) {
				children.set(i, c);
				return;
			}
		}
	}

	@Override
	public Category add(Category category) {
		return categoryDao.add(category);
	}

	@Override
	public List<Key> getSubcategoryKeys(Key categoryKey) {
		List<Key> list = new ArrayList<Key>();
		list.add(categoryKey);
		list.addAll(findAllChildren(categoryKey));
		return list;
	}

	private List<Key> findAllChildren(Key key) {
		List<Key> results = new ArrayList<Key>();
		List<Key> list = categoryDao.findChildrenKeysByParentCategoryKey(key);
		if (list != null && list.size() > 0) {
			results.addAll(list);
			for (Key k : list) {
				results.addAll(findAllChildren(k));
			}
		}
		return results;
	}

	@Override
	public List<Category> getCategoriesChainByKey(Key key) {
		List<Category> list = new ArrayList<Category>();
		Category category = categoryDao.find(key);
		if (category == null) {
			return null;
		}
		list.add(category);
		Category current = category;
		for (int i = 0; i < category.getLevel() + 1; i++) {
			if (current != null && current.getParentCategoryKey() == null) {
				break;
			}
			Category c = categoryDao.find(current.getParentCategoryKey());
			if (c != null) {
				list.add(c);
			}
			current = c;
		}
		Collections.sort(list, new CategoryLevelComparator());
		return list;
	}

	@Override
	public List<CategoryVO> getCategoriesVOChainByKey(Key key) {
		List<Category> list = getCategoriesChainByKey(key);
		return new CategoryVOBuilder().createVOList(list);
	}

}
